package com.myjavalab.thread;

public class FuturePattern {
	public static void main(String[] args) {
		System.out.println("Main Begin");
		final FutureHost host = new FutureHost();
		new Thread() {
			public void run() {
				DataModel d1 = host.request(10, 'A');
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					
				}
				System.out.println("data1 = " + d1.getContent());
			}
		}.start();
		
		new Thread() {
			public void run() {
				DataModel d2 = host.request(20, 'B');
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					
				}
				System.out.println("data2 = " + d2.getContent());
			}
		}.start();
		
		new Thread() {
			public void run() {
				DataModel d3 = host.request(30, 'C');
				try {
					Thread.sleep(2000);
				} catch (InterruptedException e) {
					
				}
				System.out.println("data3 = " + d3.getContent());
			}
		}.start();
//		DataModel d1 = host.request(10, 'A');
//		DataModel d2 = host.request(20, 'B');
//		DataModel d3 = host.request(30, 'C');
//		System.out.println("Main otherJob");
//		try {
//			Thread.sleep(2000);
//		} catch (InterruptedException e) {
//			
//		}
//		System.out.println("Main otherJob end");`
//		System.out.println("data1 = " + d1.getContent());
//		System.out.println("data2 = " + d2.getContent());
//		System.out.println("data3 = " + d3.getContent());
		System.out.println("Main end");
	}
}

class FutureHost {
	public DataModel request(final int count, final char c) {
		System.out.println("	request(" + count + "," + c + ") Begin");
		final FutureData future = new FutureData();
		new Thread() {
			public void run() {
				RealData real = new RealData(count, c);
				future.setRealData(real);
			}
		}.start();
		System.out.println("	request(" + count + "," + c + ") End");
		return future;
	}
}

interface DataModel{
	public abstract String getContent();
}

class RealData implements DataModel {

	private final String content;
	public RealData(int count, char c) {
		System.out.println("	making RealData(" + count + "," + c + ") Begin");
		char[] buffer = new char[count];
		for(int i = 0; i < count; i++) {
			buffer[i] = c;
			try {
				Thread.sleep(1000);
			}catch(InterruptedException e) {
				
			}
		}
		System.out.println("	making RealData(" + count + "," + c + ") end");
		this.content = new String(buffer);
	}
	
	@Override
	public String getContent() {
		return content;
	}
}

class FutureData implements DataModel {

	private RealData realData = null;
	private boolean ready = false;
	
	public synchronized void setRealData(RealData realData) {
		if(ready) {
			return;
		}
		this.realData = realData;
		this.ready = true;
		System.out.println("RealData is ready..." + Thread.currentThread().getName());
		notifyAll();
	}
	
	@Override
	public synchronized String getContent() {
		while(!ready) {
			try{
				System.out.println(Thread.currentThread().getName() + " is waiting...");
				wait();
			}catch (InterruptedException e) {

			}
		}
		return realData.getContent();
	}
}
